#pragma once

#include "spdlog/logger.h"

template<typename... Args>
using format_string_t = spdlog::format_string_t<Args...>;
using string_view_t = spdlog::string_view_t;
using memory_buf_t = spdlog::memory_buf_t;

namespace NaturalEngine {

    enum LogLevel : int {
        Trace = 0,
        Debug = 1,
        Info = 2,
        Warn = 3,
        Error = 4,
        Levels
    };

    class Logger {
    public:
        explicit Logger(const std::string &tag);

        template<typename... Args>
        void Trace(format_string_t<Args...> fmt, Args &&...args) {
            log(LogLevel::Trace, fmt, args...);
        }

        template<typename... Args>
        void Debug(format_string_t<Args...> fmt, Args &&...args) {
            log(LogLevel::Debug, fmt, args...);
        }

        template<typename... Args>
        void Info(format_string_t<Args...> fmt, Args &&...args) {
            log(LogLevel::Info, fmt, args...);
        }

        template<typename... Args>
        void Warn(format_string_t<Args...> fmt, Args &&...args) {
            log(LogLevel::Warn, fmt, args...);
        }

        template<typename... Args>
        void Error(format_string_t<Args...> fmt, Args &&...args) {
            log(LogLevel::Error, fmt, args...);
        }

    private:
        template<typename... Args>
        void log(LogLevel lvl, format_string_t<Args...> fmt, Args &&...args) {
            memory_buf_t buf;
            fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(args...));
            log(lvl, buf);
        }

        void log(LogLevel lvl, const memory_buf_t &buf);

        std::unique_ptr<spdlog::logger> _logger;
    };

}

